import platform
from os import system
from random import choice, randint

import numpy as np


class My2048():


    def _show(self):
        

        self.clear()
        text = 'score:'+str(self.score)
        print('{:^20}\n'.format(text))
        if self.over:
            print('{:^20}'.format('Game over'))
            exit()
        
        for line in self.date:
            for cell in line:
                if not cell:
                    cell = ' '
                print('|{: ^4}'.format(cell), end = '')
            print('|',end = '')
            print('\n')

    def __init__(self):
        self.date = None
        self.score = None
        self.emtry = None
        self.systype = platform.system()
        self.cmd = {
            'Windows':'cls',
            'Linux':'clear',
        }
        self.over = False
        self.last_date_score = [None,None]
#       random.seed()

    def clear(self):
        # 清屏
        system(self.cmd[self.systype])

    def _transpose(self,postion):
        # postion {0:逆时针1次,1:顺时针1次,2:行逆序}
        def nsz(date):
            return date.T[::-1]
        def ssz(date):
            return nsz(nsz(nsz(date)))
        if postion == 2:
            self.date = self.date[::-1]
        elif postion == 0:
            self.date = nsz(self.date)
        elif postion == 1:
            self.date = ssz(self.date)
    
    def _action(self):
        for x in range(1,4):
            for y in range(4):
                if not self.date[x][y]:
                    continue
                i = 0
                for i in range(1,x+1):
                    # print(self.date[x-i][y])
                    if self.date[x-i][y]:
                        break
                else:
                    # 到边界的特殊处理,且边界一定是空的，非空会break
                    self.date[x][y] , self.date[x-i][y] = self.date[x-i][y] , self.date[x][y]
                    continue
                
                # 未到边界
                
                # while self.date[x-i][y] == 0 and x-i > 0:
                #     i += 1
                # 相同合并，否则移动
                # print('i = ',i)
                if self.date[x-i][y] == self.date[x][y]:
                    self.date[x-i][y] *= 2
                    if self.date[x-i][y] == 2048:
                        self.date[x-i][y] = 0
                    self.date[x][y] = 0
                    self.score += self.date[x-i][y]
                else:
                    i -= 1
                    self.date[x][y] , self.date[x-i][y] = self.date[x-i][y] , self.date[x][y]

    def _update(self,c):
        self.last_date_score[0] = self.date.copy()
        self.last_date_score[1] = self.score
        if c == 'w':
            self._action()
        elif c == 's':
            self._transpose(2)
            self._action()
            self._transpose(2)
        elif c == 'a':
            self._transpose(1)
            self._action()
            self._transpose(0)
        elif c == 'd':
            self._transpose(0)
            self._action()
            self._transpose(1)
    def _get_emtry(self):
        self.emtry = [ (x,y) for x in range(4) for y in range(4) if not self.date[x][y]]
        if not self.emtry:
            self.over = True
            
    def _random(self,num=1):
        self._get_emtry()
#       if num==1:return
        def _get_random_number(max):
            if max > 2:
                return choice([ 2**i for i in range(1,12) if 2**i < max])
            else:
                return 2
        for n in range(num):
            if self.emtry:
                x,y = self.emtry.pop(randint(0,len(self.emtry)-1))
                self.date[x][y]= _get_random_number(self.date.max())
                
            
                                                                                                    
    def _init(self):
        # self.date = [[ 0 for i in range(4)] for j in range(4) ]
        self.date = np.zeros((4,4),dtype = np.int32)
        self.score = 0
        
        self._random(num=2)
        
    
    def run(self):
        self._init()
        self._show()
        c = None
        while c != 'q':
            c = input()
            if not c in 'wsad':
                continue
            self._update(c)
            self._random()
            self._show()

    def _break_step(self):
        self.date = self.last_date_score[0].copy()
        self.score = self.last_date_score[1]

    def auto_play(self):
        from time import sleep
        self._init()
        self._show()
        while True:
            best_c = 'w'
            max_score = 0
            for c in 'wsad':
                self._update(c)
                max_score , best_c = (self.score , c) if self.score > max_score else (max_score , best_c)
                self._break_step()
            
            #######调式##########
            # print(best_c)
            # control = input()
            # if control == 'b':
            #     self._break_step()
            #     self._show()
            #     continue
            #####################
            self._update(best_c)
            self._random()
            self._show()
            print(best_c)
            # print(self.date.max())
            sleep(1)
            



def main():
    game = My2048()
    # game.run()
    game.auto_play()
    

main()
